package com.tv.cms.api.utils;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.SecureRandom;

public class AesEncryption {
    private static final String ALGORITHM       = "AES";
    private static final String AES_CBC = "AES/CBC/PKCS5Padding";
    private static final String myEncryptionKey = "ThisIsFoundation";
    private static final String UNICODE_FORMAT  = "UTF8";
    private static final int DEFAULT_AES_KEYSIZE = 128;
    private static final int DEFAULT_IVSIZE = 16;
    private static final SecureRandom RANDOM = new SecureRandom();
    private static final byte[] DEFAULT_KEY = new byte[]{-97, 88, -94, 9, 70, -76, 126, 25, 0, 3, -20, 113, 108, 28, 69, 125};

    /**
     * 加密
     * @param valueToEnc
     * @return
     */
    public static String encrypt(String valueToEnc) {

        byte[] encValue = new byte[0];
        try {
            Key key = generateKey();
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.ENCRYPT_MODE, key);
            encValue = c.doFinal(valueToEnc.getBytes());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String encryptedValue = new BASE64Encoder().encode(encValue);
        return encryptedValue;
    }

    /**
     * 解密
     * @param encryptedValue
     * @return
     */
    public static String decrypt(String encryptedValue) {

        byte[] decValue = new byte[0];//////////LINE 50
        try {
            Key key = generateKey();
            Cipher c = Cipher.getInstance(ALGORITHM);
            c.init(Cipher.DECRYPT_MODE, key);
            byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
            decValue = c.doFinal(decordedValue);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    private static Key generateKey() throws Exception {
        byte[] keyAsBytes;
        keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
        Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
        return key;
    }

    public static String decode(String input) {
        return new String(decode(decodeHex(input), DEFAULT_KEY), StandardCharsets.UTF_8);
    }

    public static String decode(String input, String key) {
        return new String(decode(decodeHex(input), decodeHex(key)), StandardCharsets.UTF_8);
    }

    public static String encode(String input, String key) {
        return encodeHex(encode(input.getBytes(StandardCharsets.UTF_8),genIV(), decodeHex(key)));
    }

    public static String encode(String input) {
        return encodeHex(encode(input.getBytes(StandardCharsets.UTF_8), DEFAULT_KEY));
    }

    public static byte[] encode(byte[] input, byte[] key) {
        return aes(input, key, 1);
    }

    public static byte[] encode(byte[] input, byte[] key, byte[] iv) {
        return aes(input, key, iv, 1);
    }

    public static byte[] decode(byte[] input, byte[] key) {
        return aes(input, key, 2);
    }

    private static byte[] aes(byte[] input, byte[] key, int mode) {
        try {
            SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(mode, secretKey);
            return cipher.doFinal(input);
        } catch (GeneralSecurityException var5) {
            throw unchecked(var5);
        }
    }

    private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) {
        try {
            SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance(AES_CBC);
            cipher.init(mode, secretKey, ivSpec);
            return cipher.doFinal(input);
        } catch (GeneralSecurityException var7) {
            throw unchecked(var7);
        }
    }

    public static byte[] genIV() {
        byte[] bytes = new byte[DEFAULT_IVSIZE];
        RANDOM.nextBytes(bytes);
        return bytes;
    }

    public static String genKeyString() {
        return encodeHex(genKey(DEFAULT_AES_KEYSIZE));
    }

    public static byte[] genKey(int keysize) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
            keyGenerator.init(keysize);
            SecretKey secretKey = keyGenerator.generateKey();
            return secretKey.getEncoded();
        } catch (GeneralSecurityException var3) {
            throw unchecked(var3);
        }
    }

    public static byte[] decodeHex(String input) {
        try {
            return Hex.decodeHex(input.toCharArray());
        } catch (DecoderException var2) {
            throw unchecked(var2);
        }
    }
    public static RuntimeException unchecked(Exception e) {
        return e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException(e);
    }
    public static String encodeHex(byte[] input) {
        return new String(Hex.encodeHex(input));
    }
}

